package cn.kgc.util.desensitization;

import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.IOException;

/**
 * @author YC
 */
@AllArgsConstructor
@NoArgsConstructor
public class SensitiveInfoSerializer extends JsonSerializer<String> implements ContextualSerializer {

    /**
     * 脱敏数据类型
     */
    private DesensitizationType type;
    /**
     * 被脱敏数据前位不脱敏字符长度
     */
    private Integer prefixLength;
    /**
     * 被脱敏数据后位不脱敏字符长度
     */
    private Integer suffixLength;

    /**
     * 将字符串类型的属性值进行脱敏
     *
     * @param s                  当前数据属性值
     * @param jsonGenerator      json生成器
     * @param serializerProvider 序列化器提供者
     * @throws IOException 序列化异常
     */
    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (!s.isEmpty()) {
            // 判断当前数据的脱敏类型，结合Hoot提供的工具进行处理
            switch (type) {
                case PHONE:
                    s = DesensitizedUtil.mobilePhone(s);
                    break;
                case CHINESE_NAME:
                    s = DesensitizedUtil.chineseName(s);
                    break;
                case ID_CARD_NUM:
                    s = DesensitizedUtil.idCardNum(s, prefixLength, suffixLength);
                    break;
                default:
                    // hide方法第三个参数是从第几个字符往后不被覆盖
                    s = StrUtil.hide(s, prefixLength, s.length() - suffixLength);
                    break;
            }
        }
        jsonGenerator.writeString(s);
    }

    /**
     * 根据属性类型返回不同的序列化器
     *
     * @param serializerProvider 序列化器提供者
     * @param beanProperty       脱敏数据的属性（包含注解的元数据）
     * @return 序列化器
     * @throws JsonMappingException 序列化异常
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            // 获取注解的属性信息
            Desensitization annotation = beanProperty.getAnnotation(Desensitization.class);
            if (annotation != null) {
                return new SensitiveInfoSerializer(annotation.type(), annotation.prefixLength(), annotation.suffixLength());
            }
        }
        return null;
    }

}
